#ifndef THREAD_POOL_H
#define THREAD_POOL_H

#include<vector>
#include<queue>
#include<atomic>
#include<functional>      // std::function
#include<thread>          // std::thread
#include<mutex>
#include<condition_variable>
#include<iostream>

class ThreadPool{

public:
    using Task = std::function<void()>;
    ThreadPool(int threadNum);
    ~ThreadPool();
    void addThread();

    void commit(std::function<void()> f);
    // 返回空闲线程数目
    int idleCount() const {return m_idleThrNum;}
    // 线程数量
    int threadNum() const {return m_pools.size();}

private:
    int m_threadNum = 1;                 //初始化线程数量
    std::queue<Task> m_tasks;            //任务队列
    std::vector<std::thread> m_pools;    //线程池
    std::mutex m_mutex;                  //任务队列同步锁

    std::condition_variable m_cv;         //条件阻塞
    std::atomic<bool> m_run{true};        //线程池是否运行
    std::atomic<int> m_idleThrNum;        //空闲线程数量
};


ThreadPool::ThreadPool(int threadNum):m_threadNum(threadNum){
    addThread();
}

ThreadPool::~ThreadPool(){
    std::cout<<"~ThreadPool"<<std::endl;
    m_run = false;
    m_cv.notify_all();   //唤醒所有线程执行
    for(auto& thr : m_pools){
        if(thr.joinable()){
            thr.join();  //等待任务结束
        }
    }
}

void ThreadPool::addThread(){
    for(int i=0;i<m_threadNum;++i){
        m_pools.emplace_back([this](){
            // 工作线程
            while(true){
                Task task;   
                {
                    std::unique_lock<std::mutex> lock(m_mutex);
                    m_cv.wait(lock, [this]{
                        return !m_run || (!m_tasks.empty());
                    });
                    if( !m_run && (m_tasks.empty())){
                        return;   //工作线程结束
                    }
                    m_idleThrNum--;
                    task = std::move(m_tasks.front());
                    m_tasks.pop();
                }
                task();
                {
                    std::unique_lock<std::mutex> lock(m_mutex);
                    m_idleThrNum++;
                }
            }
        });
    }
}


void ThreadPool::commit(std::function<void()> f){
    {
        std::lock_guard<std::mutex> lock(m_mutex);
        m_tasks.emplace(f);
        m_cv.notify_one();
    }
}


#endif